package com.gxsyh.nantie.login.provider.controller;

import com.google.common.collect.Maps;
import com.gxsyh.nantie.commons.configure.rabbitmq.RabbitMQConfig;
import com.gxsyh.nantie.commons.dto.ResponseResult;
import com.gxsyh.nantie.commons.dto.SendLogResult;
import com.gxsyh.nantie.commons.utils.MapperUtils;
import com.gxsyh.nantie.commons.utils.OkHttpClientUtil;
import com.gxsyh.nantie.login.provider.controller.dto.LoginParam;
import com.gxsyh.nantie.login.provider.domain.TbUser;
import com.gxsyh.nantie.login.provider.service.TbUserService;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @email yom535@outlook.com
 * @author: 刘锋嘉(Liu Fengjia)
 * @date: 2020/1/2
 * @time: 11:36
 * @Description:
 */
@RestController
public class LoginController {
    @Resource
    TokenStore tokenStore;

    @Resource(name = "userDetailsServiceBean")
    UserDetailsService userDetailsService;

    @Resource
    BCryptPasswordEncoder passwordEncoder;

    @Value("${server.port}")
    String ServerPort;


    @Resource
    RedisTemplate redisTemplate;

    @Resource
    TbUserService tbUserService;

    @Resource
    AmqpTemplate amqpTemplate;

    private static final Logger logger = LoggerFactory.getLogger(LoginController.class);

    @PostMapping(value = "/users/login")
    public ResponseResult<Map<String, Object>> login(@RequestBody LoginParam loginParam, HttpServletResponse httpServletResponse,HttpServletRequest request){
        String URL_OAUTH_TOKEN="http://127.0.0.1:"+ServerPort+"/oauth/token";

        String sessionCode="captcha"+loginParam.getCodeUUID();


        if (sessionCode==null){
            logger.error("验证码错误");
            httpServletResponse.setStatus(400);
            return new ResponseResult<Map<String, Object>>(400,"验证码错误",null);
        }

        ValueOperations valueOperations = redisTemplate.opsForValue();
        String captcha = (String) valueOperations.get(sessionCode);

        // 判断验证码
        if (loginParam.getCode() == null||captcha==null || !captcha.equals(loginParam.getCode().trim().toLowerCase())) {
            logger.error("验证码不正确");
            httpServletResponse.setStatus(400);
            return new ResponseResult<Map<String, Object>>(400,"验证码不正确",null);
        }
        //验证码正确才可以后面的操作
        else {
            redisTemplate.delete(sessionCode);
            Map<String,String> params= Maps.newHashMap();
            params.put("username", loginParam.getUsername());
            params.put("password", loginParam.getPassword());
            params.put("grant_type", "password");
            params.put("client_id", "client");
            params.put("client_secret", "secret");
            UserDetails userDetails=null;
            try {
                userDetails=userDetailsService.loadUserByUsername(loginParam.getUsername());

                if (userDetails==null||!passwordEncoder.matches(loginParam.getPassword(),userDetails.getPassword()))
                {
                    logger.error("用户名或密码错误");
                    httpServletResponse.setStatus(400);
                    return new ResponseResult<Map<String, Object>>(400,"用户名或密码错误",null);
                }
            }catch (Exception e){
                logger.error("用户名或密码错误");
                httpServletResponse.setStatus(400);
                return new ResponseResult<Map<String, Object>>(400,"用户名或密码错误",null);
            }
            try {
                Response response = OkHttpClientUtil.getInstance().postData(URL_OAUTH_TOKEN, params);
                String jsonString= Objects.requireNonNull(response.body()).string();
                Map<String, Object> jsonMap = MapperUtils.json2map(jsonString);
                String token = String.valueOf(jsonMap.get("access_token"));
                String refresh_token = String.valueOf(jsonMap.get("refresh_token"));
                tbUserService.updateOneTbUserByRefresh_token(loginParam.getUsername(),refresh_token);
                Map<String,Object> result=Maps.newHashMap();
                result.put("token",token);
//                使用消息队列发送日志
                SendLogResult sendLogResult = new SendLogResult();
                sendLogResult.setUserId(Long.valueOf(userDetails.getUsername()));
                sendLogResult.setUsername(loginParam.getUsername());
                sendLogResult.setInfo("登录后台系统");
                amqpTemplate.convertAndSend(RabbitMQConfig.SEND_LOG_QUEUE,sendLogResult);
//                end消息队列发送日志
                return new ResponseResult<Map<String, Object>>(HttpStatus.OK.value(),"登录成功",result);

            } catch (Exception e) {
                e.printStackTrace();
            }
            logger.error("登录失败");
            httpServletResponse.setStatus(400);
            return new ResponseResult<>(400,"登录失败",null);
        }



    }

    /**
     * 获取验证码
     * @param response
     * @throws Exception
     */
    @GetMapping("/users/login/captcha")
    public ResponseResult<Map<String,String>> captcha( HttpServletResponse response) throws Exception {

        // 三个参数分别为宽、高、位数
        SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
        // 设置字体
        specCaptcha.setFont(new Font("Verdana", Font.PLAIN, 32));  // 有默认字体，可以不用设置
        // 设置类型，纯数字、纯字母、字母数字混合
        specCaptcha.setCharType(Captcha.TYPE_DEFAULT);
        String uuid = UUID.randomUUID().toString();

//        对应的UUID 和 验证码 写进redis
        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set("captcha"+uuid,specCaptcha.text().toLowerCase(),120, TimeUnit.SECONDS);

        // 输出图片base64编码
        String imageBase64 = specCaptcha.toBase64();
        Map<String, String> captcha=new HashMap();
        captcha.put("image",imageBase64);
        captcha.put("codeUUID",uuid);
        return new ResponseResult<>(HttpStatus.OK.value(),"验证码获取成功",captcha);
    }


    /**
     * 手机登录
     * @param loginParam
     * @param httpServletResponse
     * @param request
     * @return
     */
    @PostMapping(value = "/users/phone/login")
    public ResponseResult<Map<String, Object>> phoneLogin(@RequestBody LoginParam loginParam, HttpServletResponse httpServletResponse,HttpServletRequest request){

        String URL_OAUTH_TOKEN="http://127.0.0.1:"+ServerPort+"/oauth/token";

        String sessionCode="captcha"+loginParam.getCodeUUID();


        if (sessionCode==null){
            logger.error("验证码错误");
            httpServletResponse.setStatus(400);
            return new ResponseResult<Map<String, Object>>(400,"验证码错误",null);
        }

        ValueOperations valueOperations = redisTemplate.opsForValue();
        String captcha = (String) valueOperations.get(sessionCode);

        // 判断验证码
        if (loginParam.getCode() == null||captcha==null || !captcha.equals(loginParam.getCode().trim().toLowerCase())) {
            logger.error("验证码不正确");
            httpServletResponse.setStatus(400);
            return new ResponseResult<Map<String, Object>>(400,"验证码不正确",null);
        }
        //验证码正确才可以后面的操作
        else {
            redisTemplate.delete(sessionCode);
            Map<String,String> params= Maps.newHashMap();
            params.put("username", loginParam.getUsername());
            params.put("password", loginParam.getPassword());
            params.put("grant_type", "password");
            params.put("client_id", "phone");
            params.put("client_secret", "secretphone");
            UserDetails userDetails=null;
            try {
                userDetails=userDetailsService.loadUserByUsername(loginParam.getUsername());

                if (userDetails==null||!passwordEncoder.matches(loginParam.getPassword(),userDetails.getPassword()))
                {
                    logger.error("用户名或密码错误");
                    httpServletResponse.setStatus(400);
                    return new ResponseResult<Map<String, Object>>(400,"用户名或密码错误",null);
                }
            }catch (Exception e){
                logger.error("用户名或密码错误");
                httpServletResponse.setStatus(400);
                return new ResponseResult<Map<String, Object>>(400,"用户名或密码错误",null);
            }
            try {
                Response response = OkHttpClientUtil.getInstance().postData(URL_OAUTH_TOKEN, params);
                String jsonString= Objects.requireNonNull(response.body()).string();
                Map<String, Object> jsonMap = MapperUtils.json2map(jsonString);
                String token = String.valueOf(jsonMap.get("access_token"));
                String refresh_token = String.valueOf(jsonMap.get("refresh_token"));
                tbUserService.updateOneTbUserByRefresh_token(loginParam.getUsername(),refresh_token);
                Map<String,Object> result=Maps.newHashMap();
                result.put("token",token);
//                使用消息队列发送日志
                SendLogResult sendLogResult = new SendLogResult();
                sendLogResult.setUserId(Long.valueOf(userDetails.getUsername()));
                sendLogResult.setUsername(loginParam.getUsername());
                sendLogResult.setInfo("登录后台系统");
                amqpTemplate.convertAndSend(RabbitMQConfig.SEND_LOG_QUEUE,sendLogResult);
//                end消息队列发送日志
                return new ResponseResult<Map<String, Object>>(HttpStatus.OK.value(),"登录成功",result);

            } catch (Exception e) {
                e.printStackTrace();
            }
            logger.error("登录失败");
            httpServletResponse.setStatus(400);
            return new ResponseResult<>(400,"登录失败",null);
        }



    }



    //内部注销
    @GetMapping(value = "/users/logout")
    public ResponseResult<Void> groupLogout(@RequestParam String userId){
        Collection<OAuth2AccessToken> client = tokenStore.findTokensByClientIdAndUserName("client", userId);
        for (OAuth2AccessToken oAuth2AccessToken : client) {
            tokenStore.removeAccessToken(oAuth2AccessToken);
        }

        return new ResponseResult<>(HttpStatus.OK.value(),"删除token成功",null);
    }
    //用户界面注销
    @GetMapping(value = "/users/logout/now")
    public ResponseResult<Void> logout(){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Collection<OAuth2AccessToken> client = tokenStore.findTokensByClientIdAndUserName("client", authentication.getName());
        for (OAuth2AccessToken oAuth2AccessToken : client) {
            tokenStore.removeAccessToken(oAuth2AccessToken);
        }
        return new ResponseResult<>(HttpStatus.OK.value(),"注销成功",null);
    }
}
